<?php

namespace mybackend\controllers;

use common\error\ErrorCode;
use common\traits\LogActionTrait;
use mybackend\models\MyAdminIdentity;
use Yii;
use yii\filters\AccessControl;
use yii\web\Response;
use common\error\ErrorMsg;
use common\services\myhtsq\RoleService;
use common\entities\myhtsq\ActionCode;
use common\support\LogHelper;

/**
 * 控制器基类
 */
Abstract class BaseController extends YiiPerformanceRecordController {
    use LogActionTrait;
    /* --------- 明源的动作权限校验 -begin-------- */

    private $filteredActions = [];  //需要权限校验的action名称
    private $forbiddenActions = [];
    private $allowActions = [];
    private $cacheKeyPrefix = 'cacheControllerRoleAuthRule_';
    protected $userId; //登录用户id

    /**
     * 明源动作权限设置规则
     * 通过重写roleAuthRules方法，设置动作点授权配置（目前只支持allow=true）
     * 注意：actions：不带'action',
     * example:
      protected function roleAuthRules(){
      return [
      'actions'=>['A','B','C','D','E'],
      'rules'=>
      [[
      'allow'=>true,
      'actionCodeMaps'=>[
      'A'=>ActionCode::BASE_BUILDING_ADD,
      'B'=>ActionCode::SYS_ROLE_ADD,
      'C'=>ActionCode::SYS_ROLE_EDIT
      ]
      ],[
      'allow'=>true,
      'actions'=>['D','E'],
      'actionCodes'=>[
      ActionCode::BASE_BUILDING_EDIT,
      ActionCode::SYS_ROLE_DELETE
      ]
      ]
      ]
      ];
      }
     * @return multitype:multitype:string  multitype:boolean multitype:string  multitype:boolean multitype:string
     */

    protected function roleAuthRules() {
        return [];
    }

    private function loadRoleAuthRules($controller) {
        if (count($this->filteredActions) > 0) {
            return;
        }
        $name = \get_class($controller);
        $cachekey = $this->cacheKeyPrefix . $name;

        if (Yii::$app->cache->exists($cachekey)) {
            $cache = Yii::$app->cache->get($cachekey);
            $this->filteredActions = $cache['filteredActions'];
            $this->allowActions = $cache['allowActions'];
            $this->forbiddenActions = $cache['forbiddenActions'];
            return;
        }

        $roleRules = $this->roleAuthRules();
        if (empty($roleRules)) {
            return;
        }

        $isvalid = false;
        if (isset($roleRules['actions']) && isset($roleRules['rules']) && \is_array($roleRules['actions']) && \is_array($roleRules['rules'])) {
            $isvalid = true;
        }

        if ($isvalid === false) {
            return;
        }

        $actions = $roleRules['actions'];
        foreach ($actions as $idx => $value) {
            $key = 'action' . \strtolower($value);
            if (!\array_key_exists($key, $this->filteredActions)) {
                \array_push($this->filteredActions, $key);
            }
        }

        $roleRuleItems = $roleRules['rules'];
        if (isset($roleRuleItems) && isset($roleRuleItems['allow']) && $roleRuleItems['allow'] == 1) {
            $this->convertRoleRule($roleRuleItems);
        } else if (isset($roleRuleItems)) {
            foreach ($roleRuleItems as $idx => $roleRule) {
                $this->convertRoleRule($roleRule);
            }
        }

        Yii::$app->cache->set($cachekey, [
            'filteredActions' => $this->filteredActions,
            'allowActions' => $this->allowActions,
            'forbiddenActions' => $this->forbiddenActions
                ], 36000);
    }

    private function convertRoleRule($roleRule) {
        if ($roleRule['allow'] === true) {
            if (isset($roleRule['actionCodeMaps']) && \is_array($roleRule['actionCodeMaps'])) {
                foreach ($roleRule['actionCodeMaps'] as $key => $value) {
                    $keytmp = 'action' . \strtolower($key);
                    if (\array_key_exists($keytmp, $this->allowActions)) {
                        \array_push($this->allowActions[$keytmp], $value);
                    } else {
                        $this->allowActions[$keytmp] = [$value];
                    }
                }
            }
            if (isset($roleRule['actions']) && isset($roleRule['actionCodes']) && \is_array($roleRule['actions']) && \is_array($roleRule['actionCodes'])) {
                foreach ($roleRule['actions'] as $key => $value) {
                    foreach ($roleRule['actionCodes'] as $key2 => $value2) {
                        $keytmp = 'action' . \strtolower($value);
                        if (\array_key_exists($keytmp, $this->allowActions)) {
                            \array_push($this->allowActions[$keytmp], $value2);
                        } else {
                            $this->allowActions[$keytmp] = [$value2];
                        }
                    }
                }
            }
        } else {
            //todo:此场景先不考虑
        }
    }

    /**
     * 判断action是否有权限
     * @param string $action 动作名称
     * @return boolean 是否有权限
     */
    private function checkActionAccess($action) {
        //如果action不需要授权校验，返回true
        if (empty($this->filteredActions) || !\in_array($action, $this->filteredActions)) {
            return true;
        }

        if (\array_key_exists($action, $this->allowActions)) {
            foreach ($this->allowActions[$action] as $key => $value) {
                //只要有一个配置有权限，则返回true
                if (RoleService::checkLoginUserAccess($value)) {
                    return true;
                }
            }
        }

        return false;
    }

    /* --------- 明源的动作权限校验 -begin-------- */

    /**
     * 是否开启csrf检测
     */
    public $enableCsrfValidation = false;

    /**
     * 输出json格式数据
     * @param string|bool|array $data
     * @param bool $success
     */
    protected function json($data, $success = true) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        if ($success === false) {
            Yii::$app->response->setStatusCode(500);
        }
        Yii::$app->response->data = $data;

        \Yii::$app->end();
    }

    /**
     * 输出json格式数据
     * @param string|bool|array $data 输出数据
     * @param string|int $retCode 自定义错误码
     * @param string $errMsg 错误信息
     * @param bool $sucess 是否设置500错误码
     */
    protected function exportJson($data = [], $retCode = 0, $errMsg = '', $sucess = true) {
        Yii::$app->response->format = Response::FORMAT_JSON;
        if ($sucess === false) {
            Yii::$app->response->setStatusCode(500);
        }
        $exportData['data'] = $data;
        $exportData['retCode'] = $retCode;
        $exportData['errMsg'] = $errMsg;

        Yii::$app->response->data = $exportData;

        \Yii::$app->end();
    }

    /**
     * 错误参数公用方法
     * @param array $params
     */
    protected function errorParam(array $params = [])
    {
        Yii::$app->response->format = Response::FORMAT_JSON;
        if ($params) {
            $msg = sprintf('参数：%s 不能为空。', implode('、', $params));
            $data = ['retCode' => ErrorCode::ERR_PARAMS_ERR, 'errMsg' => $msg];
        } else {
            $data = ['retCode' => ErrorCode::ERR_PARAMS_ERR, 'errMsg' => ErrorMsg::getErrMsg(ErrorCode::ERR_PARAMS_ERR)];
        }

        Yii::$app->response->data = $data;
        Yii::$app->end();
    }

    /**
     * 必须使用post请求公用方法
     */
    protected function exitIfNotPost() {
        if (!\Yii::$app->request->isPost) {
            Yii::$app->response->format = Response::FORMAT_JSON;
            $data = ['retCode' => ErrorCode::ERR_REQUEST_MUST_POST, 'errMsg' => ErrorMsg::getErrMsg(ErrorCode::ERR_REQUEST_MUST_POST)];
            Yii::$app->response->data = $data;
            \Yii::$app->end();
        }
    }

    /**
     * 重定向
     * @param string $url
     * @param bool $exit
     * @return Response|static
     */
    public function redirect($url, $exit = true) {
        $result = Yii::$app->response->redirect($url);
        Yii::$app->end();
        return $result;
    }

    public function getRequest() {
        return Yii::$app->request;
    }

    public function getResponse() {
        return Yii::$app->response;
    }

    public function behaviors() {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ]
        ];
    }

    /**
     * 返回是否ajax请求
     */
    public function isAjaxRequest() {
        return $this->getRequest()->getIsAjax();
    }

    /**
     * @return MyAdminIdentity
     */
    protected function getUserIdentity() {
        return \Yii::$app->user->identity;
    }

    public function beforeAction($action) {
        $this->logAction($action);
        $result = parent::beforeAction($action);

        if ($result) {
            //behaviors校验通过：该action设置了不登陆可以访问，或者设置登陆才能访问但现在已经是登陆状态
            if (!Yii::$app->user->isGuest) {
                //只有是登陆状态才需要校验明源动作权限
                $this->loadRoleAuthRules($action->controller);
                $key = \strtolower($action->actionMethod);
                if (!$this->checkActionAccess($key)) {
                    $this->json(array(
                        "retCode" => ErrorCode::ERR_USER_FUNCTION_NOT_AUTHORIZED,
                        "errMsg" => "当前用户没有此功能的授权"
                    ));
                    Yii::$app->end();
                    return false;
                }
            }
        } else {
            if ($this->isAjaxRequest()) {
                Yii::$app->getResponse()->clear();
                $this->json(array(
                    "retCode" => ErrorCode::ERR_KFSADMIN_NOT_LOGIN,
                    "errMsg" => "请先登录"
                ));
                Yii::$app->end();
                return false;
            }
        }
        return $result;
    }

    /**
     * 获取get或post参数
     * @param string $name
     * @param string $method
     * @param string $defaultValue 默认值
     * @return array|string
     */
    protected function getParam($name, $method = "get", $defaultValue = '') {
        if ($method == "post") {
            return $this->getRequest()->post($name, $defaultValue);
        }
        return $this->getRequest()->get($name, $defaultValue);
    }

}
